內在的隱藏語言
Rust有一個秘密:實際上它 是兩種語言合而為一。雖然安全的Rust是你的守護者,但Rust編譯器本質上是 保守的。它遵循嚴格的哲學:寧可拒絕一個正確且安全的程式,也不願不小心允許一個危險的程式。這造成硬體能做的事與編譯器能證明的事之間出現了差距。
嚴謹的現實
想像編譯器就像一位嚴格的守門人。在這個程式碼範例中,match條件判斷式 if y 適用於整個模式群組 (4 | 5 | 6)。這種嚴格的 優先順序 反映了借用檢查器(Borrow Checker)的運作方式;它對你的記憶體套用全局且不容妥協的規則。然而,底層的電腦硬體卻是 本質上不安全;它無法理解「擁有權」或「生命週期」的概念。要打造像 split_at_mut這樣的高效能工具,我們必須進入 非安全Rust 『逃生口』,以執行技術上正確但邏輯上過於複雜、超出編譯器靜態分析能力的操作。
紅色與綠色圓圈之間的差距,正是非安全Rust存在的地方——當靜態分析失敗時,讓我們得以發揮硬體的全部潛能。
main.py
TERMINALbash — 80x24
> Ready. Click "Run" to execute.
>
QUESTION 1
What is the primary reason for the existence of Unsafe Rust?
To allow programmers to write C code in Rust.
Because static analysis is conservative and may reject valid code.
To disable the borrow checker entirely for the whole project.
Because hardware is naturally safe and doesn't need checks.
✅ Correct!
The compiler prefers false positives (rejecting safe code) over false negatives (accepting unsafe code).❌ Incorrect
Unsafe Rust is a controlled 'escape hatch' specifically for when the compiler's proof-engine is too limited.QUESTION 2
In the pattern
4 | 5 | 6 if y, what does the guard if y apply to?Only the value 6.
Only the values 5 and 6.
The entire pattern group (4, 5, and 6).
It depends on the value of x.
✅ Correct!
Match guards have lower precedence than the 'or' operator in patterns.❌ Incorrect
The guard acts on the combined group (4 | 5 | 6).QUESTION 3
Does Unsafe Rust turn off the borrow checker?
Yes, it disables all safety checks within the block.
No, it only provides 'superpowers' like raw pointer dereferencing.
Yes, but only for variables declared inside the block.
No, it actually makes the borrow checker stricter.
✅ Correct!
The borrow checker is still active; unsafe blocks just let you perform specific actions it otherwise forbids.❌ Incorrect
Common misconception! Unsafe blocks only grant specific capabilities like dereferencing raw pointers.QUESTION 4
Why is computer hardware considered 'inherently unsafe'?
It lacks the ability to execute instructions.
It does not understand Rust's ownership and lifetime rules.
Hardware is prone to physical failure.
Hardware requires a garbage collector to function.
✅ Correct!
Hardware works with raw addresses and registers; it has no concept of 'borrowing' or 'safety'.❌ Incorrect
The issue is the abstraction gap: hardware deals with bits and addresses, not Rust's safety guarantees.QUESTION 5
Which scenario necessitates an unsafe block?
Sorting a vector of integers.
Splitting a mutable slice into two non-overlapping parts.
Creating a new HashMap.
Using a match statement with a guard.
✅ Correct!
The compiler cannot prove that the two resulting slices won't overlap, even if the logic is correct.❌ Incorrect
Standard collections and sorting use safe Rust (or wrap unsafe code in safe APIs for you).Unsafe Logic & Safe Wrappers
Bridging the gap between Proof and Reality
You are implementing a performance-critical buffer that requires raw memory access to interact with a hardware I/O port. The compiler rejects your code because it involves aliasing pointers that it cannot verify as safe.
Q
Explain why it is standard practice to wrap 'unsafe' code in a safe function.
Solution:
By wrapping unsafe code in a safe function, we encapsulate the risk. The developer manually verifies the invariants (like bounds checking), allowing users of the API to benefit from the performance of unsafe code without having to use 'unsafe' blocks themselves.
By wrapping unsafe code in a safe function, we encapsulate the risk. The developer manually verifies the invariants (like bounds checking), allowing users of the API to benefit from the performance of unsafe code without having to use 'unsafe' blocks themselves.
Q
In the context of the 'split_at_mut' example, what is the 'contract' the developer must fulfill?
Solution:
The developer must ensure that the two resulting mutable slices truly do not overlap in memory. If they do overlap, it would cause data races or undefined behavior, which 'unsafe' allows but the developer must prevent.
The developer must ensure that the two resulting mutable slices truly do not overlap in memory. If they do overlap, it would cause data races or undefined behavior, which 'unsafe' allows but the developer must prevent.